package com.haobangs.imms.mqttUtils.mqtt;


import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.haobangs.imms.domain.AlarmRecord;
import com.haobangs.imms.domain.Device;
import com.haobangs.imms.domain.Factory;
import com.haobangs.imms.domain.Workshop;
import com.haobangs.imms.mapper.AlarmRecordMapper;
import com.haobangs.imms.mapper.FactoryMapper;
import com.haobangs.imms.mapper.WorkshopMapper;
import com.haobangs.imms.service.IDeviceService;
import com.haobangs.imms.smsUtils.AliyunSmsService;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.concurrent.*;

/**
 * @Author HaoBangs
 * @Date 2023年 06月 20日 17: 10
 * @Description 处理MQTT负载消息
 **/
@Slf4j
@Component
public class HandleMqttPayload {
    private static ExecutorService executorService = new ThreadPoolExecutor(15, 20, 60L,
            TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());

    @Autowired
    private IDeviceService deviceService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private AlarmRecordMapper alarmRecordMapper;

    @Autowired
    private AliyunSmsService aliyunSmsService;

    @Autowired
    private WorkshopMapper workshopMapper;

    @Autowired
    private FactoryMapper factoryMapper;

    @Autowired
    private ISysUserService sysUserService;

    private boolean hasSentOrangeAlert = false; // 是否已发送过橙色警报
    private boolean hasSentRedAlert = false; // 是否已发送过红色警报
    private Date lastOrangeAlertTime = null; // 上一次发送橙色警报的时间
    private Date lastRedAlertTime = null; // 上一次发送红色警报的时间

    public void handleMqttPayloadPool(String payload){
        executorService.execute(() ->{
            if(JSONUtil.isJson(payload)){
                JSONObject payloadJson = JSONUtil.parseObj(payload);
                String deviceSerialNumber = payloadJson.getStr("deviceSerialNumber");
                Device payloadDevice = deviceService.selectDeviceBySerialNumber(deviceSerialNumber);
                Workshop workshop = workshopMapper.selectById(payloadDevice.getWorkshopId());
                Factory factory = factoryMapper.selectById(workshop.getFactoryId());
                String status = payloadJson.getStr("status");
                if(StringUtils.isEmpty(status)){
                    Float value = payloadJson.getFloat("value");
                    if(value == null){
                        status = "2";
                    }else{
                        switch (deviceSerialNumber) {
                            case "imms_42":
                                status = (value > 0.8) ? "1" : "0";
                                break;
                            case "imms_30":
                                status = (value < -100.0) ? "1" : "0";
                                break;
                            case "imms_18":
                                status = (value < -100.0) ? "1" : "0";
                                break;
                            case "imms_36":
                                status = (value > 0.8 ) ? "1" : "0";
                                break;
                            default:
                                status = "2";
                                break;
                        }
                    }
                }
                String alarmInfo = payloadJson.getStr("alarmInfo");
                Long edgeTimeLong = payloadJson.getLong("edgeTime");
                Date edgeTime = DateUtil.date(edgeTimeLong * 1000L);
                String edgeTimeString = DateUtil.format(edgeTime, "yyyy-MM-dd HH:mm:ss");
                // 震动传感器数据发送信息
//                if (deviceSerialNumber.equals("imms_77")) {
//                    float floatValue = Float.parseFloat(status);
//                    if (floatValue > 3.5) {
//                        Date currentTime = new Date();
//                        if (floatValue <= 6.5 && !hasSentOrangeAlert) {
//                            if (lastOrangeAlertTime == null || DateUtil.between(lastOrangeAlertTime, currentTime, DateUnit.HOUR) >= 5) {
//                                String zhenalarmInfo = "震动传感器橙色警报，当前传感器值为：" + floatValue + "mm/s";
//                                List<String> senders = StrUtil.split(workshop.getAlarmSender(), ",");
//                                sendAlarmMessage(senders, factory.getFactoryName(), zhenalarmInfo, edgeTimeString);
//
//                                hasSentOrangeAlert = true;
//                                lastOrangeAlertTime = currentTime; // 更新上一次发送橙色警报的时间为当前时间
//                            }
//                        } else if (floatValue > 6.5 && !hasSentRedAlert) {
//                            if (lastRedAlertTime == null || DateUtil.between(lastRedAlertTime, currentTime, DateUnit.HOUR) >= 5) {
//                                String zhenalarmInfo = "震动传感器红色警报，当前传感器值为：" + floatValue + "mm/s";
//                                List<String> senders = StrUtil.split(workshop.getAlarmSender(), ",");
//                                sendAlarmMessage(senders, factory.getFactoryName(), zhenalarmInfo, edgeTimeString);
//
//                                hasSentRedAlert = true;
//                                lastRedAlertTime = currentTime; // 更新上一次发送红色警报的时间为当前时间
//                            }
//                        }
//                    } else {
//                        hasSentOrangeAlert = false; // 重置橙色警报标记
//                        hasSentRedAlert = false; // 重置红色警报标记
//                    }
//                }
//                   MQTT数据从1—>0时 存入告警信息
                if(checkDeviceStatuschange(deviceSerialNumber,status,payloadDevice.getWorkshopId()) && "1".equals(payloadDevice.getIsAlarm())){
                    AlarmRecord alarmRecord = new AlarmRecord();
                    alarmRecord.setFactoryId(payloadDevice.getFactoryId());
                    alarmRecord.setWorkshopId(payloadDevice.getWorkshopId());
                    alarmRecord.setEdgeId(payloadDevice.getEdgeId());
                    alarmRecord.setDeviceName(payloadDevice.getDeviceName());
                    alarmRecord.setDeviceSerialNumber(payloadDevice.getDeviceSerialNumber());
                    alarmRecord.setEdgeTime(edgeTime);
                    alarmRecord.setContent(alarmInfo);
                    alarmRecord.setStatus(status);
                    alarmRecord.setCreateTime(DateUtils.getNowDate());
                    alarmRecordMapper.insert(alarmRecord);
                    log.info("记录了新的设备修复好"+deviceSerialNumber);
                }
                // 优化：将Status存入redis，先判断MQTT传过来的Status和Redis中的数据是否相同，相同不更改数据库，不同修改
                if(checkDeviceStatus(deviceSerialNumber,status,payloadDevice.getWorkshopId())){
//                   MQTT数据从0—>1时 存入告警信息
                    if("1".equals(status) && "1".equals(payloadDevice.getIsAlarm())){
                            AlarmRecord alarmRecord = new AlarmRecord();
                            alarmRecord.setFactoryId(payloadDevice.getFactoryId());
                            alarmRecord.setWorkshopId(payloadDevice.getWorkshopId());
                            alarmRecord.setEdgeId(payloadDevice.getEdgeId());
                            alarmRecord.setDeviceName(payloadDevice.getDeviceName());
                            alarmRecord.setDeviceSerialNumber(payloadDevice.getDeviceSerialNumber());
                            alarmRecord.setEdgeTime(edgeTime);
                            alarmRecord.setContent(alarmInfo);
                            alarmRecord.setStatus(status);
                            alarmRecord.setCreateTime(DateUtils.getNowDate());
                            alarmRecordMapper.insert(alarmRecord);
                            List<String> senders = StrUtil.split(workshop.getAlarmSender(), ",");
                            sendAlarmMessage(senders, factory.getFactoryName(), alarmInfo, edgeTimeString);
                    }
                    payloadDevice.setData(payload);
                    payloadDevice.setEdgeTime(edgeTime);
                    payloadDevice.setStatus(status);
                    deviceService.updateDevice(payloadDevice);
                }
            }else {
                log.error("MQTT payload 数据格式不是Json：" + payload);
                throw new RuntimeException("数据格式非Json");
            }

        });
    }

    private void sendAlarmMessage(List<String> senders, String factoryName, String alarmInfo, String edgeTime) {
        for (String send : senders) {
            SysUser user = sysUserService.selectUserById(Long.parseLong(send));
            if (StringUtils.isNotNull(user) && StringUtils.isNotNull(user.getPhonenumber())){
                aliyunSmsService.sendCodeAsync(user.getPhonenumber(),factoryName,alarmInfo,edgeTime);
            }
        }
    }
    /*
    * 判断Redis中的设备状态和获取的设备状态是否相同
    * */
    public Boolean checkDeviceStatus(String deviceSerialNumber,String status,Long workshopId){
        String redisDeviceStatus = redisCache.getCacheMapValue(Constants.DEVICE_STATUS + workshopId, deviceSerialNumber);
        if(StringUtils.isNull(redisDeviceStatus) || !redisDeviceStatus.equals(status)){
            redisCache.setCacheMapValue(Constants.DEVICE_STATUS + workshopId, deviceSerialNumber, status);
            return true;
        }else {
            return false;
        }
    }

    /*
     * 判断Redis中的设备状态和获取的设备状态是否从1变成了0
     * */
    public Boolean checkDeviceStatuschange(String deviceSerialNumber,String status,Long workshopId){
        String redisDeviceStatus = redisCache.getCacheMapValue(Constants.DEVICE_STATUS + workshopId, deviceSerialNumber);
        if(!StringUtils.isNull(redisDeviceStatus) ){
            if("0".equals(status)&& "1".equals(redisDeviceStatus)){

//                redisCache.setCacheMapValue(Constants.DEVICE_STATUS + workshopId, deviceSerialNumber, status);
                return true;
            }else {
                return false;
            }
        }else {
            return false;
        }
    }
}
